<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JS029-正则表达式-注册案例</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
</head>
<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }

    body {
        background-color: #222;
        color: snow;
    }

    li {
        margin-left: 1rem;
        line-height: 1.8;
    }

    a {
        color: darkgray;
        text-decoration: none;

        &:hover {
            color: snow;
        }
    }

    .container {
        margin: 1rem;
        padding: 1rem;
        border: 1px solid silver;
        overflow-y: auto;
        scrollbar-width: none;

        display: flex;
        flex-direction: column;
        align-items: start;
        gap: 1rem;
    }

    .register-form {
        display: flex;
        flex-direction: column;
        gap: .5rem;

        .input-box {
            position: relative;
            display: flex;
            align-items: center;
            justify-content: start;
            gap: .5rem;
            text-wrap: nowrap;

            .input-head {
                width: 4rem;
                text-align: right;
            }

            .input-body {
                position: relative;
                width: 12rem;

                input {
                    width: 100%;
                    padding: .5rem;
                    background-color: #333;
                    border: 2px solid gray;
                    border-radius: .4rem;

                    color: snow;
                    font-size: 1rem;
                }

                a.get-code {
                    position: absolute;
                    right: .5rem;
                    height: 100%;

                    display: inline-flex;
                    align-items: center;

                    font-size: .8rem;
                }
            }

            .input-foot {
                position: absolute;
                left: 102%;
                overflow: hidden;
                display: none;

                &.warning {
                    color: lightcoral;
                }

                &.checked {
                    color: lightgreen;
                }
            }
        }

        .eula-box {
            display: flex;
            justify-content: end;
            gap: .2rem;
        }

        button.submit {
            height: 2.5rem;
            margin-top: .5rem;
            background-color: green;
            border: 2px solid lightgreen;
            border-radius: .4rem;

            font-size: 1rem;
            color: snow;

            &:active {
                background-color: darkgreen;
                border-color: limegreen;
            }
        }

        @media (max-width: 35rem) {
            .input-box {
                margin-bottom: 1.5rem;

                .input-foot {
                    top: 2.6rem;
                    left: 4.6rem;
                }
            }

            button.submit {
                margin-top: 0;
            }
        }
    }
</style>
<body>
<div class="container">
    <h1 class="title">JS029-正则表达式-注册案例</h1>
    <ul>
        <li>用户名：6-16字符，只能使用英文字母a-z或A-Z、数字0-9、连字符-或下划线_。</li>
        <li>手机号：使用中国大陆手机号(+86)格式。前3位有要求，后8位没有，后8位全填1即可(debug)。</li>
        <li>验证码：固定为 11111，“获取验证码”按钮仅有交互逻辑(debug)。</li>
        <li>密码：6-20字符，其他同用户名。</li>
    </ul>
    <form action="" class="register-form">
        <div class="input-box uname" data-field="uname">
            <span class="input-head">用户名</span>
            <label class="input-body"><input required type="text" maxlength="16"></label>
            <span class="input-foot warning"><i class="fa-solid fa-circle-exclamation"></i>用户名格式有误</span>
            <span class="input-foot checked"><i class="fa-solid fa-circle-check"></i>用户名有效</span>
        </div>
        <div class="input-box phone-number" data-field="phone-number">
            <span class="input-head">手机号</span>
            <label class="input-body"><input required type="text" maxlength="11"></label>
            <span class="input-foot warning"><i class="fa-solid fa-circle-exclamation"></i>手机号格式有误</span>
            <span class="input-foot checked"><i class="fa-solid fa-circle-check"></i>手机号有效</span>
        </div>
        <div class="input-box verify-code" data-field="verify-code">
            <span class="input-head">验证码</span>
            <label class="input-body">
                <input required type="text" maxlength="5">
                <a href="javascript:" class="get-code">获取验证码</a>
            </label>
            <span class="input-foot warning"><i class="fa-solid fa-circle-exclamation"></i>验证码有误</span>
            <span class="input-foot checked"><i class="fa-solid fa-circle-check"></i>验证码正确</span>
        </div>
        <div class="input-box passwd" data-field="passwd">
            <span class="input-head">密码</span>
            <label class="input-body"><input required type="password" maxlength="20"></label>
            <span class="input-foot warning"><i class="fa-solid fa-circle-exclamation"></i>密码格式有误</span>
            <span class="input-foot checked"><i class="fa-solid fa-circle-check"></i>密码有效</span>
        </div>
        <div class="input-box confirm-passwd" data-field="confirm-passwd">
            <span class="input-head">确认密码</span>
            <label class="input-body"><input required type="password" maxlength="20"></label>
            <span class="input-foot warning"><i class="fa-solid fa-circle-exclamation"></i>两次输入密码不一致</span>
            <span class="input-foot checked"><i class="fa-solid fa-circle-check"></i></span>
        </div>
        <label class="eula-box">
            <input required type="checkbox" class="eula">我同意<a href="javascript:">最终用户协议(EULA)</a>
        </label>
        <button class="submit">注册</button>
    </form>
</div>
<script>
    (function initRegisterFormEl() {
        const registerFormEl = document.querySelector('.register-form');
        const inputBoxFieldElMap = new Map();
        registerFormEl.querySelectorAll('.input-box').forEach(el => {
            inputBoxFieldElMap.set(el.dataset.field, el);
        });
        const inputBoxElPassableMap = new Map();
        inputBoxFieldElMap.forEach((el) => {
            inputBoxElPassableMap.set(el, false);
        });

        registerFormEl.addEventListener('submit', (e) => {
            e.preventDefault();
            let passFactorEl = registerFormEl.querySelector('input.eula');
            let pass = passFactorEl.checked;
            for (const [el, isPassable] of inputBoxElPassableMap) {
                if (!pass) break;
                passFactorEl = el;
                pass = isPassable;
            }
            if (pass) alert('you pass!');
            else alert(`you shall not pass... because of [${passFactorEl.classList}].`);
        });

        initInputBoxEl(inputBoxFieldElMap.get('uname'), () => {
        }, (el) => {
            return checkIfInputBoxElIsPassableWithRegex(el, /^[a-zA-Z0-9-_]{6,16}$/);
        });
        initInputBoxEl(inputBoxFieldElMap.get('phone-number'), () => {
        }, (el) => {
            return checkIfInputBoxElIsPassableWithRegex(el,
                /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/);
        });
        initInputBoxEl(inputBoxFieldElMap.get('verify-code'), (el) => {
            const getCodeEl = el.querySelector('.get-code');
            let clickLock = false;
            getCodeEl.addEventListener('click', function () {
                if (clickLock) return;
                clickLock = true;
                let cooldownSeconds = 5;
                this.innerText = cooldownSeconds + '秒后重新获取';
                let cooldownTimerId = setInterval(() => {
                    if (--cooldownSeconds <= 0) {
                        this.innerText = '重新获取';
                        clearInterval(cooldownTimerId);
                        clickLock = false;
                    } else this.innerText = cooldownSeconds + '秒后重新获取';
                }, 1000);
            });
        }, (el) => {
            return el.querySelector('input').value === '11111';
        });

        initInputBoxEl(inputBoxFieldElMap.get('passwd'), () => {
        }, (el) => {
            inputBoxFieldElMap.get('confirm-passwd').querySelector('input').dispatchEvent(new Event('change'));
            return checkIfInputBoxElIsPassableWithRegex(el, /^[a-zA-Z0-9-_]{6,20}$/);
        });

        initInputBoxEl(inputBoxFieldElMap.get('confirm-passwd'), () => {
        }, (el) => {
            return el.querySelector('input').value
                === inputBoxFieldElMap.get('passwd').querySelector('input').value;
        });

        function checkIfInputBoxElIsPassableWithRegex(el, regex) {
            return regex.test(el.querySelector('input').value);
        }

        function initInputBoxEl(el, initFn, isPassableFn) {
            initFn(el);
            el.querySelector('input').addEventListener('change', () => {
                let pass = isPassableFn(el);
                inputBoxElPassableMap.set(el, pass);
                el.querySelector('.input-foot.warning').style.display = pass ? 'none' : 'block';
                el.querySelector('.input-foot.checked').style.display = pass ? 'block' : 'none';
            });
        }
    })();
</script>
</body>
</html>